
#include <bur/plctypes.h>

#ifdef _DEFAULT_INCLUDES
	#include <AsDefault.h>
#endif
#include <AsBrStr.h>
#include <string.h>


//	EPROM mapping:
//	address:	structure:
//	0x0000		DCD_TYPE
//	0x2000		LLM_MOTOR_DCD_TYPE
//	0x4000		LLM_PHASE_DCD_TYPE[42]
//	0x6000		LLM_MAGSENS_DCD_TYPE[41]




void _CYCLIC ProgramCyclic(void)
{

	// get act date/time for logging
	DTGetTimeAct.enable = 1;
	DTGetTime(&DTGetTimeAct);
	DateTimeAct = DTGetTimeAct.DT1;
	// get act timestamp for checking timeout
	TimeAct = clock_ms();
	
	
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// auto calib sequence
	
	if(gAssembly.Ready == 0)
	{
		gAutoCalibAMR.CmdCalib = 0;
		gAutoCalibAMR.CmdCheck = 0;
	}

	if((gAutoCalibAMR.CmdCalib == 0) && (gAutoCalibAMR.CmdCheck == 0))
	{
		AutoStep = 0;
		gAutoCalibAMR.Active = 0;
	}

	switch(AutoStep)
	{
		case 0:
			if((gAutoCalibAMR.CmdCalib) || (gAutoCalibAMR.CmdCheck))
			{
				gAutoCalibAMR.Active++;
				if(gAutoCalibAMR.Segment[gAutoCalibAMR.Active] != 0)
				{
					AutoStep = 1;
				}
				else
				{
					gAutoCalibAMR.Active = 0;
					gAutoCalibAMR.CmdCalib = 0;
					gAutoCalibAMR.CmdCheck = 0;
				}
			}
			gAutoCalibAMR.MoveSequenceIndex = gCalibAMR.MoveSequenceIndex;		// keep MoveSequenceIndex remanent
		break;
		
		case 1:
//			gAssembly.EnableSctrl		= 1;
			gAssembly.EnableCalibAMR	= 1;
			gAssembly.Power				= 1;
			AutoStep++;
		break;
		case 2:
			if(gAssembly.Ready)
			{
				AutoStep = 10;
			}
		break;

		case 10:
			gCalibAMR.Segment = gAutoCalibAMR.Segment[gAutoCalibAMR.Active];
			gCalibAMR.CmdLoadEprom = 1;
			AutoTime = TimeAct;
			AutoStep++;
		break;
		case 11:
			if((TimeAct - AutoTime) > 100)
			{
				if((gCalibAMR.Busy == 0) && (gCalibAMR.CmdLoadEprom == 0))
				{
					AutoStep++;
				}
			}
		break;
		case 12:
			if(gCalibAMR.Data.MagSensNum > 0)
			{
				AutoSensor = 0;
				AutoStep = 20;
			}
		break;
		
		case 20:
			if(AutoSensor == 0)
				AutoSensor = 1;
			else
				AutoSensor += 5;
		
			if(AutoSensor <= gCalibAMR.Data.MagSensNum)
			{
				gCalibAMR.Sensor = AutoSensor;
				AutoStep++;
			}
			else
			{
				AutoStep = 30;
			}
		break;
		case 21:
			if(gShuttleMove.Velocity > 0.5)
			{
				gShuttleMove.Velocity = 0.5;
			}
			gCalibAMR.CmdStartMove = 1;
			AutoTime = TimeAct;
			AutoStep++;
		break;
		case 22:
			if((TimeAct - AutoTime) > 500)
			{
				if((gCockpTrace.Done) && (gShuttleMove.Sequence[gCalibAMR.MoveSequenceIndex].ActiveStep == 0))
				{
					AutoTime = TimeAct;
					AutoStep++;
				}
			}
		break;
		case 23:
			if((TimeAct - AutoTime) > 500)
			{
				AutoStep = 20;
			}
		break;
		
		case 30:
			if(gAutoCalibAMR.CmdCalib)
				gCalibAMR.CmdCalcNewCorr = 1;
			if(gAutoCalibAMR.CmdCheck)
				gCalibAMR.CmdCalcCheckCorr = 1;
			AutoTime = TimeAct;
			AutoStep++;
		break;
		case 31:
			if((TimeAct - AutoTime) > 100)
			{
				if((gCalibAMR.Busy == 0) && (gCalibAMR.CmdCalcNewCorr == 0) && (gCalibAMR.CmdCalcCheckCorr == 0))
				{
					if(gAutoCalibAMR.CmdCalib)
					{
						AutoStep = 40;
					}
					else if(gAutoCalibAMR.CmdCheck)
					{
						AutoStep = 50;
					}
				}
			}
		break;
		
		case 40:
			gCalibAMR.CmdBurnEprom = 1;
			AutoTime = TimeAct;
			AutoStep++;
		break;
		case 41:
			if((TimeAct - AutoTime) > 100)
			{
				if((gCalibAMR.Busy == 0) && (gCalibAMR.CmdBurnEprom == 0))
				{
					AutoStep = 50;
				}
			}
		break;
		
		case 50:
			AutoTime = TimeAct;
			AutoStep++;
		break;
		case 51:
			if((TimeAct - AutoTime) > 2000)
			{
				AutoStep = 0;
			}
		break;
	
	}




	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// single commands

	if(gCalibAMR.MoveSequenceIndex > MAX_NUM_MOVESEQ)	gCalibAMR.MoveSequenceIndex = MAX_NUM_MOVESEQ;
	if(gCalibAMR.MoveSequenceIndex < 1)					gCalibAMR.MoveSequenceIndex = 1;
		
	if(gCalibAMR.Sensor == 0)
		gCalibAMR.Sensor = 1;
	if(gCalibAMR.Data.MagSensNum >= 5)
	{
		if(gCalibAMR.Sensor > (gCalibAMR.Data.MagSensNum - 4))
			gCalibAMR.Sensor = (gCalibAMR.Data.MagSensNum - 4);
	}
	else
		gCalibAMR.Sensor = 1;
		

	switch(Step)
	{
	
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// COMMAND

		case AMR_COMMAND:
			if(gCalibAMR.CmdPlcReset)
			{
				gCalibAMR.CmdPlcReset = 0;
				SYSreset(1,0x01);
			}
			if(DiagCpuIsSimulated() == 0)		// using real hardware only
			{
				if(LlmSegment[gCalibAMR.Segment] != 0)		// segment defined
				{
					if(LogDataBusy == 0)
					{
						if(gCalibAMR.Segment != EdgeSegment)
						{
							EdgeSegment = gCalibAMR.Segment;
							gCalibAMR.LockCmdBurn	= 1;
							gCalibAMR.LockCmdLoad	= 0;
							gCalibAMR.LockCmdCheck	= 1;
							gCalibAMR.CmdLoadEprom	= 1;
						}
						
						// EPROM commands
						if((gCalibAMR.CmdBurnEprom) && (gCalibAMR.LockCmdBurn == 0))
						{
							Step = AMR_BURN_DCD;
						}
						else if((gCalibAMR.CmdLoadEprom) && (gCalibAMR.LockCmdLoad == 0))
						{
							Step = AMR_LOAD_DCD;
						}
						else if((gCalibAMR.CmdCheckEprom) && (gCalibAMR.LockCmdCheck == 0))
						{
							Step = AMR_CHECK_DCD;
						}
						else if(gCalibAMR.CmdResetCorr)
						{
							gCalibAMR.CmdResetCorr = 0;
							Step = AMR_RESET_CORR_VALUES;
						}
						else if(gCalibAMR.CmdCalcNewCorr)
						{
							gCalibAMR.CmdCalcNewCorr = 0;
							BypassRawCorrForCalc = 0;
							Step = AMR_CALC_PREPARE;
						}
						else if(gCalibAMR.CmdCalcCheckCorr)
						{
							gCalibAMR.CmdCalcCheckCorr = 0;
							BypassRawCorrForCalc = 1;
							Step = AMR_CALC_PREPARE;
						}
						else if(gCalibAMR.CmdDeleteTraceData)
						{
							gCalibAMR.CmdDeleteTraceData = 0;
							Step = AMR_DEL_TD_INIT;
						}
						
						// optional command - remove if not available in application
						if((gCalibAMR.CmdConfigureTrace) || (gCalibAMR.CmdStartMove))
						{
							gCalibAMR.CmdConfigureTrace = 0;
							
							brsstrcpy((UDINT)&gCockpTracePar.File.FileName, (UDINT)&gCalibAMR.Trace.FileName);
							
							gCockpTracePar.Timing.TotalRecordingTime	= gCalibAMR.Trace.Timing.TotalRecordingTime;
							gCockpTracePar.Timing.TriggerOffsetTime		= gCalibAMR.Trace.Timing.TriggerOffsetTime;
							gCockpTracePar.Timing.AcpSampleTime			= gCalibAMR.Trace.Timing.AcpSampleTime;
							
							brsstrcpy((UDINT)&gCockpTracePar.StartTrigger[0].DataPointName, (UDINT)&gCalibAMR.Trace.StartTrigger.DataPointName);
							gCockpTracePar.StartTrigger[0].Condition	= gCalibAMR.Trace.StartTrigger.Condition;
							gCockpTracePar.StartTrigger[0].Threshold	= gCalibAMR.Trace.StartTrigger.Threshold;
							gCockpTracePar.StartTrigger[0].Window		= gCalibAMR.Trace.StartTrigger.Window;
							
							for(i=0;i<=49;i++)
							{
								brsstrcpy((UDINT)&gCockpTracePar.DataPointName[i],(UDINT)&gCalibAMR.Trace.DataPointName[i]);
							}
						}
						// optional command - remove if not available in application
						if(gCalibAMR.CmdStartMove)
						{
							gCalibAMR.CmdStartMove = 0;
							gShuttleMove.Sequence[gCalibAMR.MoveSequenceIndex].TraceAutoStart = 1;
							gShuttleMove.Sequence[gCalibAMR.MoveSequenceIndex].StartOnce = 1;
						}
						
						if(Step != AMR_COMMAND)
						{
							gCalibAMR.Done		= 0;
							gCalibAMR.Busy		= 1;
							gCalibAMR.Error		= 0;
							gCalibAMR.ErrorID	= 0;
						}
					}
				}
			}
		break;


		
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// burn EEPROM DCD data

		case AMR_BURN_DCD:
				Step = AMR_ERROR;
		break;

		
		
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// load EEPROM DCD data
		
		case AMR_LOAD_DCD:
			
			brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Loading EPROM data...Initializing");

			ActiveSegment = gCalibAMR.Segment;

			EpromCmdAbort	= 1;
			EpromID			= 0;
			EpromBlockIndex	= 0;
			
			
			// ParID sequence for initializing reading of data
			LoadParListWriteInit[0].ParID				= mcACPPAR_EPROM_ID;
			LoadParListWriteInit[0].VariableAddress		= (UDINT)&EpromID;
			LoadParListWriteInit[0].DataType			= mcACPTRAK_SEG_PARTYPE_UINT;

			LoadParListWriteInit[1].ParID				= mcACPPAR_EPROM_BLOCK_INDEX;
			LoadParListWriteInit[1].VariableAddress		= (UDINT)&EpromBlockIndex;
			LoadParListWriteInit[1].DataType			= mcACPTRAK_SEG_PARTYPE_UINT;


			// ParID sequence for reading data
			ParListRecordIndex = 0;

			LoadParListReadData[ParListRecordIndex].ParID			= mcACPPAR_EPROM_BLOCK;
			LoadParListReadData[ParListRecordIndex].VariableAddress	= (UDINT)&EpromBlockSize;
			LoadParListReadData[ParListRecordIndex].DataType		= mcACPTRAK_SEG_PARTYPE_VOID;
			ParListRecordIndex++;

			if((EPROM_DATA_SIZE % 6) == 0)
				EpromBlockNumber = EPROM_DATA_SIZE/6;
			else
				EpromBlockNumber = (EPROM_DATA_SIZE/6) + 1;

			for(i=0;i<EpromBlockNumber;i++)
			{
				if(i < (EpromBlockNumber - 1))
				{
					LoadParListReadData[ParListRecordIndex].ParID			= mcACPPAR_RD_BLOCK_SEGM;
					LoadParListReadData[ParListRecordIndex].VariableAddress	= (((UDINT)&EpromDataLoad) + i*6);
					LoadParListReadData[ParListRecordIndex].DataType		= mcACPTRAK_SEG_PARTYPE_VOID;
					ParListRecordIndex++;
				}
				else
				{
					LoadParListReadData[ParListRecordIndex].ParID			= mcACPPAR_RD_BLOCK_LAST_SEGM;
					LoadParListReadData[ParListRecordIndex].VariableAddress	= (((UDINT)&EpromDataLoad) + i*6);
					LoadParListReadData[ParListRecordIndex].DataType		= mcACPTRAK_SEG_PARTYPE_VOID;
					ParListRecordIndex++;
				}
			}
			
			ParListRecordsTotal		= ParListRecordIndex;
			ParListRecordsRemaining	= ParListRecordIndex;
			ParListRecordIndex		= 0;
			ParListRecordsAtOnce	= PAR_LIST_RECORDS_AT_ONCE_MAX;

						
			TimeStart = TimeAct;
			Step = AMR_LOAD_DCD_PREPARE;
		break;

		case AMR_LOAD_DCD_PREPARE:
			
			MCSegmentParListWrite.Segment			= (McSegmentType*)LlmSegment[ActiveSegment];
			MCSegmentParListWrite.DataAddress		= (UDINT)&LoadParListWriteInit;
			MCSegmentParListWrite.NumberOfParIDs	= 2;
			MCSegmentParListWrite.Mode				= mcACPTRAK_SEG_PARID_SET;
			MCSegmentParListWrite.ChannelIndex		= 0;
			MCSegmentParListWrite.Execute			= 1;

			TimeStop = TimeAct;
			
			if(MCSegmentParListWrite.Done)
			{
				MCSegmentParListWrite.Execute = 0;
				TimeStart = TimeAct;
				Step = AMR_LOAD_DCD_PAR_TRANSFER;
			}
			else if(MCSegmentParListWrite.Error)
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Loading EPROM data ERROR FUB");
				ErrorID = MCSegmentParListWrite.ErrorID;
				Step = AMR_ERROR;
			}
			else if((TimeStop - TimeStart) > EPROM_TIMEOUT)
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Loading EPROM data Timeout");
				ErrorID = 0x80000001;
				Step = AMR_ERROR;
			}
		break;

		case AMR_LOAD_DCD_PAR_TRANSFER:
			
			MCSegmentParListRead.Segment		= (McSegmentType*)LlmSegment[ActiveSegment];
			MCSegmentParListRead.DataAddress	= (UDINT)&LoadParListReadData[ParListRecordIndex];
			MCSegmentParListRead.NumberOfParIDs	= ParListRecordsAtOnce;
			MCSegmentParListRead.Mode			= mcACPTRAK_SEG_PARID_GET;
			MCSegmentParListRead.ChannelIndex	= 0;
			MCSegmentParListRead.Execute		= 1;

			TimeStop = TimeAct;
			
			i= ParListRecordIndex * 100 / ParListRecordsTotal;
			brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Loading EPROM data...");
			brsitoa(i, (UDINT)&TempString);		brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&TempString);
			brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&"% in progress");

			if(MCSegmentParListRead.Done)
			{
				MCSegmentParListRead.Execute = 0;
				ParListRecordIndex += ParListRecordsAtOnce;
				ParListRecordsRemaining-= ParListRecordsAtOnce;
				Step = AMR_LOAD_DCD_CONTROL;
			}
			else if(MCSegmentParListRead.Error)
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Loading EPROM data ERROR FUB");
				ErrorID = MCSegmentParListRead.ErrorID;
				Step = AMR_ERROR;
			}
			else if((TimeStop - TimeStart) > EPROM_TIMEOUT)
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Loading EPROM data Timeout");
				ErrorID = 0x80000001;
				Step = AMR_ERROR;
			}
		break;

		case AMR_LOAD_DCD_CONTROL:
			
			if(ParListRecordsRemaining == 0) 
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Loading EPROM data Done");
				if(gCalibAMR.CmdBurnEprom)
				{
					Step = AMR_CHECK_DCD;
				}
				else if(gCalibAMR.CmdLoadEprom)
				{
					// copy new loaded data to burn-data
					brsmemcpy((UDINT)&EpromDataBurn, (UDINT)&EpromDataLoad, sizeof(EpromDataBurn));

					// refresh parameter structure with new loaded data
					brsmemcpy((UDINT)&gCalibAMR.Data.OrderID,				(UDINT)&EpromDataBurn[0x0000],	sizeof(gCalibAMR.Data.OrderID));
					brsmemcpy((UDINT)&gCalibAMR.Data.RevisionID,			(UDINT)&EpromDataBurn[0x0018],	sizeof(gCalibAMR.Data.RevisionID));
					brsmemcpy((UDINT)&gCalibAMR.Data.SerialNr,				(UDINT)&EpromDataBurn[0x001C],	sizeof(gCalibAMR.Data.SerialNr));
					brsmemcpy((UDINT)&gCalibAMR.Data.RevisionNr,			(UDINT)&EpromDataBurn[0x002C],	sizeof(gCalibAMR.Data.RevisionNr));
					brsmemcpy((UDINT)&gCalibAMR.Data.MinFwVersion,			(UDINT)&EpromDataBurn[0x0034],	sizeof(gCalibAMR.Data.MinFwVersion));
					brsmemcpy((UDINT)&gCalibAMR.Data.MacID,					(UDINT)&EpromDataBurn[0x003C],	sizeof(gCalibAMR.Data.MacID));
					brsmemcpy((UDINT)&gCalibAMR.Data.PlkID,					(UDINT)&EpromDataBurn[0x0042],	sizeof(gCalibAMR.Data.PlkID));
					brsmemcpy((UDINT)&gCalibAMR.Data.MissionEndTime,		(UDINT)&EpromDataBurn[0x0044],	sizeof(gCalibAMR.Data.MissionEndTime));
					brsmemcpy((UDINT)&gCalibAMR.Data.PhaseNum,				(UDINT)&EpromDataBurn[0x0060],	sizeof(gCalibAMR.Data.PhaseNum));
					brsmemcpy((UDINT)&gCalibAMR.Data.AxNum,					(UDINT)&EpromDataBurn[0x0061],	sizeof(gCalibAMR.Data.AxNum));
					brsmemcpy((UDINT)&gCalibAMR.Data.SegmentType,			(UDINT)&EpromDataBurn[0x0062],	sizeof(gCalibAMR.Data.SegmentType));
					brsmemcpy((UDINT)&gCalibAMR.Data.AxType,				(UDINT)&EpromDataBurn[0x0063],	sizeof(gCalibAMR.Data.AxType));
					brsmemcpy((UDINT)&gCalibAMR.Data.MagSensType,			(UDINT)&EpromDataBurn[0x0238],	sizeof(gCalibAMR.Data.MagSensType));
					brsmemcpy((UDINT)&gCalibAMR.Data.MagSensFullyEquipped,	(UDINT)&EpromDataBurn[0x0239],	sizeof(gCalibAMR.Data.MagSensFullyEquipped));
					brsmemcpy((UDINT)&gCalibAMR.Data.MagSensNum,			(UDINT)&EpromDataBurn[0x023A],	sizeof(gCalibAMR.Data.MagSensNum));
					brsmemcpy((UDINT)&gCalibAMR.Data.SegmentLenght,			(UDINT)&EpromDataBurn[0x2000],	sizeof(gCalibAMR.Data.SegmentLenght));
					
					for(i=0;i<=40;i++)
					{
						brsmemcpy((UDINT)&gCalibAMR.Data.MagSens[i].Equipped,			(UDINT)&EpromDataBurn[(0x6000 + (i*160))],	sizeof(gCalibAMR.Data.MagSens[0].Equipped));
						brsmemcpy((UDINT)&gCalibAMR.Data.MagSens[i].PositionNominal,	(UDINT)&EpromDataBurn[(0x6004 + (i*160))],	sizeof(gCalibAMR.Data.MagSens[0].PositionNominal));
						brsmemcpy((UDINT)&gCalibAMR.Data.MagSens[i].PositionOffset,		(UDINT)&EpromDataBurn[(0x6008 + (i*160))],	sizeof(gCalibAMR.Data.MagSens[0].PositionOffset));
						brsmemcpy((UDINT)&gCalibAMR.Data.MagSens[i].CosGainCorr,		(UDINT)&EpromDataBurn[(0x600C + (i*160))],	sizeof(gCalibAMR.Data.MagSens[0].CosGainCorr));
						brsmemcpy((UDINT)&gCalibAMR.Data.MagSens[i].CosOffsetCorr,		(UDINT)&EpromDataBurn[(0x6010 + (i*160))],	sizeof(gCalibAMR.Data.MagSens[0].CosOffsetCorr));
						brsmemcpy((UDINT)&gCalibAMR.Data.MagSens[i].SinGainCorr,		(UDINT)&EpromDataBurn[(0x6014 + (i*160))],	sizeof(gCalibAMR.Data.MagSens[0].SinGainCorr));
						brsmemcpy((UDINT)&gCalibAMR.Data.MagSens[i].SinOffsetCorr,		(UDINT)&EpromDataBurn[(0x6018 + (i*160))],	sizeof(gCalibAMR.Data.MagSens[0].SinOffsetCorr));
					}
					
					brsmemcpy((UDINT)&DataMagSensLoaded, (UDINT)&gCalibAMR.Data.MagSens, sizeof(DataMagSensLoaded));
							
					gCalibAMR.LockCmdBurn	= 0;
					gCalibAMR.LockCmdLoad	= 0;
					gCalibAMR.LockCmdCheck	= 0;

					LogDataCmdWrite = 1;
					Step = AMR_DONE;
				}
			}
			else
			{
				if(ParListRecordsRemaining <= PAR_LIST_RECORDS_AT_ONCE_MAX)
					ParListRecordsAtOnce = ParListRecordsRemaining;
				else
					ParListRecordsAtOnce = PAR_LIST_RECORDS_AT_ONCE_MAX;

				TimeStart = TimeAct;
				Step = AMR_LOAD_DCD_PAR_TRANSFER;
			}
		break;



		
		
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// compare burned<=>reloaded EEPROM DCD data
		case AMR_CHECK_DCD:
			ErrorID = 0;
			for(i=0;i<(EPROM_DATA_SIZE-4);i++)
			{
				if(EpromDataBurn[i] != EpromDataLoad[i])
				{
					ErrorID = 0x80000002;
					break;
				}
			}
			if(ErrorID == 0)
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Check Data OK");
				Step = AMR_DONE;
			}
			else
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error checking data burned<=>reloaded byteIx:");
				brsitoa(i, (UDINT)&TempString);						brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&TempString);
				brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&" data-burned:");
				brsitoa(EpromDataBurn[i], (UDINT)&TempString);		brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&TempString);
				brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&" data-reloaded:");
				brsitoa(EpromDataLoad[i], (UDINT)&TempString);		brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&TempString);
				Step = AMR_ERROR;
			}
		break;



		
		
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// CALC new AMR correction values based on traced data
		case AMR_CALC_PREPARE:
			if(StatusBufferAlloc == ERR_OK)
			{
				ActiveSegment = gCalibAMR.Segment;
				ActiveSensor = 0;
				Step = AMR_CALC_PREPARE1;
			}
			else
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error alloc convert buffer");
				ErrorID = StatusBufferAlloc;
				Step = AMR_ERROR;
			}
		break;
		
		case AMR_CALC_PREPARE1:
			if(ActiveSensor < gCalibAMR.Data.MagSensNum)
			{
				ActiveSensor++;
				brsstrcpy((UDINT)&FileNameCalcOpen, (UDINT)&"Trace_AMR_Seg");	brsitoa(ActiveSegment, (UDINT)&TempString);		brsstrcat((UDINT)&FileNameCalcOpen, (UDINT)&TempString);
				brsstrcat((UDINT)&FileNameCalcOpen, (UDINT)&"_Sensor");			brsitoa(ActiveSensor, (UDINT)&TempString);		brsstrcat((UDINT)&FileNameCalcOpen, (UDINT)&TempString);
				brsstrcat((UDINT)&FileNameCalcOpen, (UDINT)&"_001.csv");
				Step = AMR_CALC_FILE_OPEN;
			}
			else
			{
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"MagSens corrections calc OK");
				LogDataCmdWrite = 3;
				Step = AMR_DONE;
			}
		break;
		
		case AMR_CALC_FILE_OPEN:
			FubFileOpen.enable	= 1;
			FubFileOpen.pDevice	= (UDINT)&"Trace";
			FubFileOpen.pFile	= (UDINT)&FileNameCalcOpen;
			FubFileOpen.mode	= fiREAD_ONLY;
			FileOpen(&FubFileOpen);
			if(FubFileOpen.status != ERR_FUB_BUSY)
			{
				if(FubFileOpen.status == ERR_OK)
				{
					if((FubFileOpen.filelen > 0) && (FubFileOpen.filelen < MAX_TRACE_FILELEN))
					{
						Step = AMR_CALC_FILE_READ;
					}
					else
					{
						brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error FileLen ");
						brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&FileNameCalcOpen);
						ErrorID = 0x80000002;
						Step = AMR_CALC_FILE_ERRORCLOSE;
					}
				}
				else if(FubFileOpen.status == fiERR_FILE_NOT_FOUND)
				{
					Step = AMR_CALC_PREPARE1;		//file not found - try next
				}
				else
				{
					brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error FileOpen ");
					brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&FileNameCalcOpen);
					ErrorID = FubFileOpen.status;
					Step = AMR_ERROR;
				}
			}
		break;
		
		case AMR_CALC_FILE_READ:
			FubFileRead.enable	= 1;
			FubFileRead.ident	= FubFileOpen.ident;
			FubFileRead.offset	= 0;
			FubFileRead.pDest	= AdrFileBuffer;
			FubFileRead.len		= FubFileOpen.filelen;
			FileRead(&FubFileRead);
			if(FubFileRead.status != ERR_FUB_BUSY)
			{
				if(FubFileRead.status == ERR_OK)
				{
					Step = AMR_CALC_FILE_CLOSE;
				}
				else
				{
					brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error FileRead ");
					brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&FileNameCalcOpen);
					ErrorID = FubFileRead.status;
					Step = AMR_CALC_FILE_ERRORCLOSE;
				}
			}
		break;
		
		case AMR_CALC_FILE_CLOSE:
			FubFileClose.enable	= 1;
			FubFileClose.ident	= FubFileOpen.ident;
			FileClose(&FubFileClose);
			if(FubFileClose.status != ERR_FUB_BUSY)
			{
				if(FubFileClose.status == ERR_OK)
				{
					Step = AMR_CALC_CORR_VALUES;
				}
				else
				{
					brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error FileClose ");
					brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&FileNameCalcOpen);
					ErrorID = FubFileClose.status;
					Step = AMR_ERROR;
				}
			}
		break;
		
		case AMR_CALC_FILE_ERRORCLOSE:
			FubFileClose.enable	= 1;
			FubFileClose.ident	= FubFileOpen.ident;
			FileClose(&FubFileClose);
			if(FubFileClose.status != ERR_FUB_BUSY)
			{
				Step = AMR_ERROR;
			}
		break;
		
		case AMR_CALC_CORR_VALUES:
			
			//extract AMR raw values from traced file-data

			brsmemset((UDINT)&CalcValue, 0, sizeof(CalcValue));

			CntFileLine			= 0;
			CntCalcValue		= 0;

			brsmemset((UDINT)&CalcValueString, 0, sizeof(CalcValueString));
			CntCalcValueStringChar	= 0;

			for(CntFileChar=0; CntFileChar<FubFileOpen.filelen; CntFileChar++)
			{
				pFileChar = (USINT*)(AdrFileBuffer+CntFileChar);
				switch(*pFileChar)
				{
					case 0x2D:		// -
					case 0x30:		// 0
					case 0x31:		// 1
					case 0x32:		// 2
					case 0x33:		// 3
					case 0x34:		// 4
					case 0x35:		// 5
					case 0x36:		// 6
					case 0x37:		// 7
					case 0x38:		// 8
					case 0x39:		// 9
						CalcValueString[CntCalcValueStringChar] = *pFileChar;
						CntCalcValueStringChar++;
					break;

					case 0x2C:		// ,
					case 0x2E:		// .
						CalcValueString[CntCalcValueStringChar] = 0x2E;
						CntCalcValueStringChar++;
					break;

					case 0x3B:		// ;
					case 0x0D:		// /r
						if((CntCalcValue >= 3) && (CntCalcValue < 13) && (CntFileLine > 0) && (CntFileLine <= 5000))
						{
							CalcValue[CntCalcValue-3].RawCnt = CntFileLine;
							CalcValue[CntCalcValue-3].Raw[CntFileLine-1] = brsatof((UDINT)&CalcValueString);
						}
						if(*pFileChar == 0x3B)
							CntCalcValue++;
						else if(*pFileChar == 0x0D)
							CntCalcValue=0;
						brsmemset((UDINT)&CalcValueString, 0, sizeof(CalcValueString));
						CntCalcValueStringChar = 0;
					break;

					case 0x0A:		// /n
						CntFileLine++;
						brsmemset((UDINT)&CalcValueString, 0, sizeof(CalcValueString));
						CntCalcValueStringChar = 0;
					break;
					
					default:
					break;

				}
			}
			
			
			
			//calc new correction data
			for(CntCalcValue=0; CntCalcValue<=9; CntCalcValue++)
			{
				
				if(CalcValue[CntCalcValue].RawCnt > 0)
				{
				
					// correction values which were used for tracing the data
					if(BypassRawCorrForCalc)
					{
						CalcValue[CntCalcValue].RawGainCorr		= 1.0;
						CalcValue[CntCalcValue].RawOffsetCorr	= 0.0;
					}
					else
					{
						if((CntCalcValue % 2) == 0)
						{
							CalcValue[CntCalcValue].RawGainCorr		= DataMagSensLoaded[(ActiveSensor-1+(CntCalcValue/2))].SinGainCorr;
							CalcValue[CntCalcValue].RawOffsetCorr	= DataMagSensLoaded[(ActiveSensor-1+(CntCalcValue/2))].SinOffsetCorr;
						}
						else
						{
							CalcValue[CntCalcValue].RawGainCorr		= DataMagSensLoaded[(ActiveSensor-1+(CntCalcValue/2))].CosGainCorr;
							CalcValue[CntCalcValue].RawOffsetCorr	= DataMagSensLoaded[(ActiveSensor-1+(CntCalcValue/2))].CosOffsetCorr;
						}
					}

					// calc new corrections
					CalcRawMax = 0.0;
					CalcRawMin = 0.0;
					for(i=0;i<CalcValue[CntCalcValue].RawCnt;i++)
					{
						if (((CalcValue[CntCalcValue].Raw[i]/CalcValue[CntCalcValue].RawGainCorr) - CalcValue[CntCalcValue].RawOffsetCorr) > CalcRawMax)
						{
							CalcRawMax = ((CalcValue[CntCalcValue].Raw[i]/CalcValue[CntCalcValue].RawGainCorr) - CalcValue[CntCalcValue].RawOffsetCorr);
						}
						else if (((CalcValue[CntCalcValue].Raw[i]/CalcValue[CntCalcValue].RawGainCorr) - CalcValue[CntCalcValue].RawOffsetCorr) < CalcRawMin)
						{
							CalcRawMin = ((CalcValue[CntCalcValue].Raw[i]/CalcValue[CntCalcValue].RawGainCorr) - CalcValue[CntCalcValue].RawOffsetCorr);
						}
					}
					CalcRawOffset = (CalcRawMax + CalcRawMin) / 2.0;
				
					CalcRawMax -= CalcRawOffset;
				
					CalcValue[CntCalcValue].GainCorr	= 1250.0 / CalcRawMax;		// gain factor for DCD
					CalcValue[CntCalcValue].OffsetCorr	= -CalcRawOffset;			// offset value for DCD
					
					// pass new calculated corrections to DCD structure
					if((CntCalcValue % 2) == 0)
					{
						gCalibAMR.Data.MagSens[(ActiveSensor-1+(CntCalcValue/2))].SinGainCorr	= CalcValue[CntCalcValue].GainCorr;
						gCalibAMR.Data.MagSens[(ActiveSensor-1+(CntCalcValue/2))].SinOffsetCorr	= CalcValue[CntCalcValue].OffsetCorr;
					}
					else
					{
						gCalibAMR.Data.MagSens[(ActiveSensor-1+(CntCalcValue/2))].CosGainCorr	= CalcValue[CntCalcValue].GainCorr;
						gCalibAMR.Data.MagSens[(ActiveSensor-1+(CntCalcValue/2))].CosOffsetCorr	= CalcValue[CntCalcValue].OffsetCorr;
					}
				}
			}

			
			
			Step = AMR_CALC_PREPARE1;
		break;
		






		case AMR_RESET_CORR_VALUES:
			for(i=0;i<=41;i++)
			{
				gCalibAMR.Data.MagSens[i].SinGainCorr	= 1.0;
				gCalibAMR.Data.MagSens[i].SinOffsetCorr	= 0.0;
				gCalibAMR.Data.MagSens[i].CosGainCorr	= 1.0;
				gCalibAMR.Data.MagSens[i].CosOffsetCorr	= 0.0;
			}
				brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"MagSens corrections reset OK");
			Step = AMR_DONE;
		break;
		



		
		
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// delete tracedata
		case AMR_DEL_TD_INIT:

			CntTraceDataDirRead = 0;
			CntTraceDataFileDelete = 0;
			brsmemset((UDINT)&ListTraceDataFile, 0, sizeof(ListTraceDataFile));
		
			Step = AMR_DEL_TD_DIRINFO;
		break;
		
		case AMR_DEL_TD_DIRINFO:
			// get list of files in Trace-Filedevice
			FubTraceDirRead.enable		= 1;
			FubTraceDirRead.pDevice		= (UDINT)&"Trace";
			FubTraceDirRead.pPath		= (UDINT)&"";
			FubTraceDirRead.entry		= CntTraceDataDirRead;
			FubTraceDirRead.option		= fiFILE;
			FubTraceDirRead.pData		= (UDINT)&ListTraceDataFile[CntTraceDataDirRead];
			FubTraceDirRead.data_len	= sizeof(ListTraceDataFile[CntTraceDataDirRead]);
		
			DirRead(&FubTraceDirRead);
			if(FubTraceDirRead.status != ERR_FUB_BUSY)
			{
				if(FubTraceDirRead.status == ERR_OK)
				{
					CntTraceDataDirRead++;
					if(CntTraceDataDirRead >= 100)
					{
						Step = AMR_DEL_TD_FILEDEL;
					}
				}
				else if(FubTraceDirRead.status == fiERR_NO_MORE_ENTRIES)
				{
					Step = AMR_DEL_TD_FILEDEL;
				}
				else
				{
					brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error TraceData DirRead ");
				//	brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&FileNameCalcOpen);
					ErrorID = FubTraceDirRead.status;
					Step = AMR_ERROR;
				}
			}
		break;
		
		case AMR_DEL_TD_FILEDEL:
			// delete trace-data files only 
			// only files starting with Trace_AMR_Seg are deleted
			if(strstr((char*)&ListTraceDataFile[CntTraceDataFileDelete].Filename[0], (char*)&"Trace_AMR_Seg"))
			{
				FubTraceFileDelete.enable	= 1;
				FubTraceFileDelete.pDevice	= (UDINT)&"Trace";
				FubTraceFileDelete.pName	= (UDINT)&ListTraceDataFile[CntTraceDataFileDelete].Filename;
				FileDelete(&FubTraceFileDelete);
				if(FubTraceFileDelete.status != ERR_FUB_BUSY)
				{
					if(FubTraceFileDelete.status == ERR_OK)
					{
						CntTraceDataFileDelete++;
						if(CntTraceDataFileDelete >= CntTraceDataDirRead)
						{
							Step = AMR_DONE;
						}
					}
					else
					{
						brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error TraceData FileDelete ");
						brsstrcat((UDINT)&gCalibAMR.Message, (UDINT)&ListTraceDataFile[CntTraceDataFileDelete].Filename);
						ErrorID = FubTraceFileDelete.status;
						Step = AMR_ERROR;
					}
				}
			}
			else
			{
				CntTraceDataFileDelete++;
				if(CntTraceDataFileDelete >= CntTraceDataDirRead)
				{
					Step = AMR_DONE;
				}
			}
		break;
		
		
		
		
		
		
		
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// ERROR
		case AMR_ERROR:
			MCSegmentParListWrite.Execute	= 0;
			MCSegmentParListRead.Execute	= 0;

			gCalibAMR.CmdBurnEprom		= 0;
			gCalibAMR.CmdLoadEprom		= 0;
			gCalibAMR.CmdCheckEprom		= 0;
			
			gCalibAMR.Done		= 0;
			gCalibAMR.Busy		= 0;
			gCalibAMR.Error		= 1;
			gCalibAMR.ErrorID	= ErrorID;
			
			Step = AMR_COMMAND;
		break;


		

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// DONE
		case AMR_DONE:
			
			MCSegmentParListWrite.Execute	= 0;
			MCSegmentParListRead.Execute	= 0;

			gCalibAMR.CmdBurnEprom		= 0;
			gCalibAMR.CmdLoadEprom		= 0;
			gCalibAMR.CmdCheckEprom		= 0;
			
			gCalibAMR.Done		= 1;
			gCalibAMR.Busy		= 0;
			gCalibAMR.Error		= 0;
			gCalibAMR.ErrorID	= 0;
			
			Step = AMR_COMMAND;
		break;


		

		// what else
		default:
		break;
	}

	
	//TODO
	TestVar = brsatof((UDINT)&CalcValueString);
//	TestVar = brsatod((UDINT)&CalcValueString);
	
	
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// FUB calls
	MC_BR_SegProcessParID_AcpTrak(&MCSegmentParListRead);
	MC_BR_SegProcessParID_AcpTrak(&MCSegmentParListWrite);
	
	
	
	
	
	
	
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Trace config
	
	gCalibAMR.SegmentPLK = LlmSegmentPLK[gCalibAMR.Segment];
	
	brsstrcpy((UDINT)&PlkString, (UDINT)&"*Acp:");
	brsstrcat((UDINT)&PlkString, (UDINT)&PlkIF);
	brsstrcat((UDINT)&PlkString, (UDINT)&".ST");
	brsitoa(gCalibAMR.SegmentPLK, (UDINT)&TempString);		brsstrcat((UDINT)&PlkString, (UDINT)&TempString);
	brsstrcat((UDINT)&PlkString, (UDINT)&"_Axis1:");

	brsstrcpy((UDINT)&gCalibAMR.Trace.FileName, (UDINT)&"Trace_AMR_Seg");	brsitoa(gCalibAMR.Segment, (UDINT)&TempString);		brsstrcat((UDINT)&gCalibAMR.Trace.FileName, (UDINT)&TempString);
	brsstrcat((UDINT)&gCalibAMR.Trace.FileName, (UDINT)&"_Sensor");			brsitoa(gCalibAMR.Sensor, (UDINT)&TempString);		brsstrcat((UDINT)&gCalibAMR.Trace.FileName, (UDINT)&TempString);
	
	gCalibAMR.Trace.Timing.TotalRecordingTime	= 0.6;
	gCalibAMR.Trace.Timing.TriggerOffsetTime	= -0.15;
	gCalibAMR.Trace.Timing.AcpSampleTime		= 0.0002;
	
	brsitoa((63711+(gCalibAMR.Sensor-1+0)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.StartTrigger.DataPointName, (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.StartTrigger.DataPointName, (UDINT)&TempString);
	
	gCalibAMR.Trace.StartTrigger.Condition	= coTRACE_GOES_ABOVE_WINDOW_EVENT;
	gCalibAMR.Trace.StartTrigger.Threshold	= 0.0;
	gCalibAMR.Trace.StartTrigger.Window		= 625.0;
	
	brsitoa((63711+(gCalibAMR.Sensor-1+0)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[0], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[0], (UDINT)&TempString);
	
	brsitoa((63712+(gCalibAMR.Sensor-1+0)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[1], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[1], (UDINT)&TempString);
	
	brsitoa((63711+(gCalibAMR.Sensor-1+1)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[2], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[2], (UDINT)&TempString);
	
	brsitoa((63712+(gCalibAMR.Sensor-1+1)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[3], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[3], (UDINT)&TempString);
	
	brsitoa((63711+(gCalibAMR.Sensor-1+2)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[4], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[4], (UDINT)&TempString);
	
	brsitoa((63712+(gCalibAMR.Sensor-1+2)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[5], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[5], (UDINT)&TempString);
	
	brsitoa((63711+(gCalibAMR.Sensor-1+3)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[6], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[6], (UDINT)&TempString);
	
	brsitoa((63712+(gCalibAMR.Sensor-1+3)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[7], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[7], (UDINT)&TempString);
	
	brsitoa((63711+(gCalibAMR.Sensor-1+4)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[8], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[8], (UDINT)&TempString);
	
	brsitoa((63712+(gCalibAMR.Sensor-1+4)*2), (UDINT)&TempString);
	brsstrcpy((UDINT)&gCalibAMR.Trace.DataPointName[9], (UDINT)&PlkString);		
	brsstrcat((UDINT)&gCalibAMR.Trace.DataPointName[9], (UDINT)&TempString);
	
	
	
	
	
	
	
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// log calib data to file
	
	switch(LogStep)
	{
	
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// COMMAND

		case AMR_COMMAND:
			LogDataBusy = 0;
			if(LogDataCmdWrite != 0)
			{
				LogDataBusy = 1;
				LogStep = AMR_LOG_DATA_PREPARE;
			}
		break;

		case AMR_LOG_DATA_PREPARE:
			brsstrcpy((UDINT)&LogDataBuffer, (UDINT)&"\r\n ");				ascDT(DateTimeAct, (UDINT)&TempString, sizeof(TempString));				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			switch(LogDataCmdWrite)
			{
				case 1:
					brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n LOAD Eprom data");
				break;
				case 2:
					brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n BURN Eprom data");
				break;
				case 3:
					brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n CALC AMR data");
				break;
			}
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n ");				

			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n Segment;");		brsitoa(gCalibAMR.SegmentPLK, (UDINT)&TempString);					brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n OrderID;");		brsstrcat((UDINT)&LogDataBuffer, (UDINT)&gCalibAMR.Data.OrderID);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n SerNr;");		brsstrcat((UDINT)&LogDataBuffer, (UDINT)&gCalibAMR.Data.SerialNr);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n Rev;");			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&gCalibAMR.Data.RevisionID);

			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n MAC-ID;");		brsitoa(gCalibAMR.Data.MacID[0], (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"-");					brsitoa(gCalibAMR.Data.MacID[1], (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"-");					brsitoa(gCalibAMR.Data.MacID[2], (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"-");					brsitoa(gCalibAMR.Data.MacID[3], (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"-");					brsitoa(gCalibAMR.Data.MacID[4], (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"-");					brsitoa(gCalibAMR.Data.MacID[5], (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);

			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n Type;");			brsitoa(gCalibAMR.Data.SegmentType, (UDINT)&TempString);			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n Length;");		brsftoa(gCalibAMR.Data.SegmentLenght, (UDINT)&TempString);			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n PhaseNum;");		brsitoa(gCalibAMR.Data.PhaseNum, (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n MagSensNum;");	brsitoa(gCalibAMR.Data.MagSensNum, (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);

			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n ");
			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n Sensor;PosNominal;PosOffset;GainCOS;OffsetCOS;GainSIN;OffsetSIN");
			if(gCalibAMR.Data.MagSensNum > 0)
			{
				for(i=0;i<gCalibAMR.Data.MagSensNum;i++)
				{
					brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n ");
					brsitoa((i+1), (UDINT)&TempString);												brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);	brsstrcat((UDINT)&LogDataBuffer, (UDINT)&";");
					brsftoa(gCalibAMR.Data.MagSens[i].PositionNominal, (UDINT)&TempString);			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);	brsstrcat((UDINT)&LogDataBuffer, (UDINT)&";");
					brsftoa(gCalibAMR.Data.MagSens[i].PositionOffset, (UDINT)&TempString);			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);	brsstrcat((UDINT)&LogDataBuffer, (UDINT)&";");
					brsftoa(gCalibAMR.Data.MagSens[i].CosGainCorr, (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);	brsstrcat((UDINT)&LogDataBuffer, (UDINT)&";");
					brsftoa(gCalibAMR.Data.MagSens[i].CosOffsetCorr, (UDINT)&TempString);			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);	brsstrcat((UDINT)&LogDataBuffer, (UDINT)&";");
					brsftoa(gCalibAMR.Data.MagSens[i].SinGainCorr, (UDINT)&TempString);				brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);	brsstrcat((UDINT)&LogDataBuffer, (UDINT)&";");
					brsftoa(gCalibAMR.Data.MagSens[i].SinOffsetCorr, (UDINT)&TempString);			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&TempString);	brsstrcat((UDINT)&LogDataBuffer, (UDINT)&";");
				}
			}

			brsstrcat((UDINT)&LogDataBuffer, (UDINT)&"\r\n \r\n \r\n \r\n \r\n ");
			
			LogDataLen = brsstrlen((UDINT)&LogDataBuffer);

			// replace "." with ","
			for(i=0;i<LogDataLen;i++)
			{
				pFileChar = (USINT*)(((UDINT)&LogDataBuffer)+i);
				if(*pFileChar == 0x2E)	// .
				{
					*pFileChar = 0x2C;	// ,
				}
			}

			LogDataCmdWrite = 0;
			LogStep = AMR_LOG_FILE_OPEN;
		break;

		case AMR_LOG_FILE_OPEN:
			FubLogFileOpen.enable	= 1;
			FubLogFileOpen.pDevice	= (UDINT)&"Trace";
			FubLogFileOpen.pFile	= (UDINT)&"LogCalibAMR.csv";
			FubLogFileOpen.mode	= fiREAD_WRITE;
			FileOpen(&FubLogFileOpen);
			if(FubLogFileOpen.status != ERR_FUB_BUSY)
			{
				if(FubLogFileOpen.status == ERR_OK)
				{
					LogFileIdent	= FubLogFileOpen.ident;
					LogFileOffset	= FubLogFileOpen.filelen;
					LogStep = AMR_LOG_FILE_WRITE;
				}
				else if(FubLogFileOpen.status == fiERR_FILE_NOT_FOUND)
				{
					LogStep = AMR_LOG_FILE_CREATE;		//file not found - create
				}
				else
				{
					brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error Log FileOpen");
					LogStep = AMR_COMMAND;
				}
			}
		break;

		case AMR_LOG_FILE_CREATE:
			FubLogFileCreate.enable		= 1;
			FubLogFileCreate.pDevice	= (UDINT)&"Trace";
			FubLogFileCreate.pFile		= (UDINT)&"LogCalibAMR.csv";
			FileCreate(&FubLogFileCreate);
			if(FubLogFileCreate.status != ERR_FUB_BUSY)
			{
				if(FubLogFileCreate.status == ERR_OK)
				{
					LogFileIdent	= FubLogFileCreate.ident;
					LogFileOffset	= 0;
					LogStep = AMR_LOG_FILE_WRITE;
				}
				else
				{
					brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error Log FileCreate");
					LogStep = AMR_COMMAND;
				}
			}
		break;

		case AMR_LOG_FILE_WRITE:
			FubLogFileWrite.enable	= 1;
			FubLogFileWrite.ident	= LogFileIdent;
			FubLogFileWrite.offset	= LogFileOffset;
			FubLogFileWrite.pSrc	= (UDINT)&LogDataBuffer;
			FubLogFileWrite.len		= LogDataLen;
			FileWrite(&FubLogFileWrite);
			if(FubLogFileWrite.status != ERR_FUB_BUSY)
			{
				if(FubLogFileWrite.status == ERR_OK)
				{
					LogStep = AMR_LOG_FILE_CLOSE;
				}
				else
				{
					brsstrcpy((UDINT)&gCalibAMR.Message, (UDINT)&"Error Log FileWrite");
					LogStep = AMR_LOG_FILE_CLOSE;
				}
			}
		break;

		case AMR_LOG_FILE_CLOSE:
			FubLogFileClose.enable	= 1;
			FubLogFileClose.ident	= LogFileIdent;
			FileClose(&FubLogFileClose);
			if(FubLogFileClose.status != ERR_FUB_BUSY)
			{
				if(FubLogFileClose.status == ERR_OK)
				{
					LogStep = AMR_COMMAND;
				}
				else
				{
					LogStep = AMR_COMMAND;
				}
			}
		break;

		// what else
		default:
		break;
	}

}








void _EXIT ProgramExit(void)
{
	if(AdrFileBuffer != 0)
		TMP_free(MAX_TRACE_FILELEN, (void**)AdrFileBuffer);
}

